package services

import beans.Publish
import beans.Record
import beans.User
import beans.UserInfo
import com.alibaba.fastjson.JSON
import com.jfinal.upload.UploadFile
import base.Message
import base.State
import common.autoreview.AutoReview
import common.autoreview.AutoReviewState
import common.permission.Permission
import common.permission.PermissionManager
import controllers.GoodsController
import models.*
import utils.ResUtils
import java.sql.Timestamp

class GoodsService(controller: GoodsController): BaseService<GoodsController>(controller){

    init {
        classificationMap = hashMapOf()
        ClassificationM.AGENT.findAll().forEach {
            val id: Int = it.getInt(ClassificationM.ID)
            val name: String = it[ClassificationM.NAME]
            classificationMap[id] = name
        }
    }

    companion object{
        lateinit var classificationMap: HashMap<Int, String>
        fun getClassificationIdByName(name: String): Int{
            classificationMap.entries.forEach {
                if (it.value == name){
                    return it.key
                }
            }
            return ClassificationM.DEFAULT_CLASS_ID
        }
    }

    /**
     * 物品发布功能代码
    * */
    fun publish(pictures: List<UploadFile>,
                title: String, desc: String, price: Double,
                classification: String,
                longitude: Double, latitude: Double, userId: Int){
        //权限检测
        if (!PermissionManager.checkUserPermission(userId, Permission.PUBLISH)){
            val message = Message(State.STATE_FAIL, data = State.getEorrorStr(State.ERROR_GOODS_NO_PUBLISH_PERMISSION))
            controller.renderJson(message)
            return
        }
        //保存图片
        val picPaths = mutableListOf<String>()
        pictures.forEach {
            val path = ResUtils.saveGoodsPic(it, it.fileName)
            path?.let {
                picPaths.add(path)
            }
        }

        val publishModel = RecordM()
        publishModel[RecordM.TITLE] = title
        publishModel[RecordM.DESC] = desc
        publishModel[RecordM.IMGS] = JSON.toJSONString(picPaths)
        publishModel[RecordM.PRICE] = price
        publishModel[RecordM.MAIN_CLASS] = getClassificationIdByName(classification)
        publishModel[RecordM.TIME] = Timestamp(System.currentTimeMillis())
        publishModel[RecordM.LONGITUDE] = longitude
        publishModel[RecordM.LATITUDE] = latitude
        publishModel[RecordM.STATE] = RecordState.REVIEW
        publishModel[RecordM.ZONE] = makeZone(longitude, latitude)
        publishModel[RecordM.USER_ID] = userId

        if (publishModel.save()){
            //请求自动审核系统
            AutoReview.checkImagesAsync(pictures.map { ResUtils.getGoodsPicLocalFile(it) }){ reviewResult ->
                if (reviewResult == AutoReviewState.PASS){
                    publishModel[RecordM.STATE] = RecordState.PASS
                } else if ( reviewResult == AutoReviewState.UNPASS) {
                    publishModel[RecordM.STATE] = RecordState.UNPASS
                }
                publishModel.update()
            }
            val message = Message(State.STATE_SUCCESS, data = "已提交物品信息, 等待审核")
            controller.renderJson(message)
        } else{
            val message = Message(State.STATE_FAIL, data = State.getEorrorStr(State.ERROR_SERVER_INSIDE_ERROR))
            controller.renderJson(message)
        }
    }

    fun getClassesList() {
        val list = classificationMap.values.toList()
        val message = Message(State.STATE_SUCCESS, data = list)
        controller.renderJson(message)
    }

    /**
     * @param longitude 经度
     * @param latitude 维度
     * @param page 分页页数
     * 根据地理位置信息，推送附近发布的物品记录
    * */
    fun pullNearPublish(longitude: String?, latitude: String?, page: Int) {
        if (longitude.isNullOrEmpty() || latitude.isNullOrEmpty()){
            pullNewPublish(page)
        } else {
            val long = longitude.toDouble()
            val lati = latitude.toDouble()
            val zones = makeFindZones(long, lati)
            val list = RecordM.findRecordInZonesWithPageAndState(zones, page, RecordState.PASS)
            if (list.isEmpty()){
                val message = Message(State.STATE_FAIL, data = State.getEorrorStr(State.ERROR_GOODS_NO_MORE_RECORD))
                controller.renderJson(message)
            } else {
                val publishList = list.map {
                    makePublishWithRecord(it)
                }
                val message = Message(State.STATE_SUCCESS, data = publishList)
                controller.renderJson(message)
            }
        }
    }

    fun pullNewPublish(page: Int) {
        val list = RecordM.findRecordWithPageAndState(page, RecordState.PASS)
        if (list.isEmpty()){
            val message = Message(State.STATE_FAIL, data = State.getEorrorStr(State.ERROR_GOODS_NO_MORE_RECORD))
            controller.renderJson(message)
        } else {
            val publishList = list.map {
                makePublishWithRecord(it)
            }
            val message = Message(State.STATE_SUCCESS, data = publishList)
            controller.renderJson(message)
        }
    }

    fun collectRecord(userId: Int, recordId: Int) {
        val model = CollectionM()
        model.set(CollectionM.USER_ID, userId)
        model.set(CollectionM.RECORD_ID, recordId)
        if (model.save()){
            val message = Message(State.STATE_SUCCESS, data = "")
            controller.renderJson(message)
        } else {
            val message = Message(State.STATE_FAIL, data = State.getEorrorStr(State.ERROR_UNKNOWN))
            controller.renderJson(message)
        }
    }

    private fun makeZone(longitude: Double, latitude: Double): String{
        val long = (longitude * 100).toInt()
        val lat = (latitude * 100).toInt()
        return "($long, $lat)"
    }

    private fun makeFindZones(longitude: Double, latitude: Double): List<String> {
        val long = (longitude * 100).toInt()
        val lat = (latitude * 100).toInt()
        return listOf("(${long-1}, ${lat-1})", "(${long}, ${lat-1})", "(${long+1}, ${lat-1})",
                      "(${long-1}, ${lat})", "(${long}, ${lat})", "(${long+1}, ${lat})",
                      "(${long-1}, ${lat+1})", "(${long}, ${lat+1})", "(${long+1}, ${lat+1})")
    }

    private fun makePublishWithRecord(record: Record): Publish{
        val userM = UserM.AGENT.findById(record.userId)
        val user = User.formModel(userM)
        val userInfoM = UserInfoM.findInfobyUserId(record.userId)
        val userInfo = UserInfo.fromModel(userInfoM)
        return Publish(user, userInfo, record)
    }

}
